package cn.com.dcsgo.controller;

import cn.com.dcsgo.api.client.NotificationClient;
import cn.com.dcsgo.api.dto.NotificationDTO;
import cn.com.dcsgo.config.validation.UserLoginByEmail;
import cn.com.dcsgo.config.validation.UserLoginByPhone;
import cn.com.dcsgo.config.validation.UserLoginByUsername;
import cn.com.dcsgo.domain.entity.User;
import cn.com.dcsgo.domain.util.UserConverter;
import cn.com.dcsgo.domain.vo.UserLoginVo;
import cn.com.dcsgo.domain.vo.UserRegisterVo;
import cn.com.dcsgo.domain.vo.UserVo;
import cn.com.dcsgo.service.UserService;
import cn.com.dcsgo.utils.ResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Random;

/**
 * UserController
 *
 * @author Dcsgo
 * @since 2025/4/3 10:31
 */
@Slf4j
@RestController
@Api(tags = "用户接口")
@RequiredArgsConstructor
@RequestMapping("user")
public class UserController {
    private final UserService userService;
    private final NotificationClient notificationClient;
    private final Random random = new Random();

    /**
     * 格式化输出
     */
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 添加登录警告通知
     *
     * @param user     user
     * @param clientIp clientIp
     * @return 添加成功 true,失败 false
     */
    private boolean addLoginWarning(User user, String clientIp) {
        NotificationDTO notificationDTO = new NotificationDTO();
        notificationDTO.setUserId(user.getId());
        notificationDTO.setType("warning");
        StringBuilder message = new StringBuilder();
        LocalDateTime now = LocalDateTime.now();
        String curTime = now.format(FORMATTER);
        message.append("账号")
                .append(user.getUsername())
                .append("于")
                .append(curTime)
                .append("在IP地址").append(clientIp)
                .append("登录，如非本人操作，请立即修改密码。");
        notificationDTO.setMessage(message.toString());
        notificationDTO.setStatus("unread");
        return notificationClient.add(notificationDTO);
    }

    @PostMapping("login/username")
    @ApiOperation("用户名登录")
    public ResponseResult<UserVo> loginByUsername(@RequestBody @Validated({UserLoginByUsername.class}) UserLoginVo user, HttpServletRequest request) {
        User result = userService.getUserByUsername(user.getUsername());
        if (result == null) {
            return ResponseResult.fail("用户名不存在");
        }
        if (!result.getPassword().equals(user.getPassword())) {
            return ResponseResult.fail("密码错误");
        }
        if (addLoginWarning(result, request.getRemoteAddr())) {
            return ResponseResult.success(new UserVo(result));
        }
        return ResponseResult.fail("通知添加失败");
    }

    @PostMapping("login/phone")
    @ApiOperation("手机号登录")
    public ResponseResult<UserVo> loginByPhone(@RequestBody @Validated({UserLoginByPhone.class}) UserLoginVo user, HttpServletRequest request) {
        User result = userService.getUserByPhone(user.getPhone());
        if (result == null) {
            return ResponseResult.fail("手机号不存在");
        }
        if (!result.getPassword().equals(user.getPassword())) {
            return ResponseResult.fail("密码错误");
        }
        if (random.nextBoolean()) {
            throw new RuntimeException("模拟随机错误");
        }
        if (addLoginWarning(result, request.getRemoteAddr())) {
            return ResponseResult.success(new UserVo(result));
        }
        return ResponseResult.fail("通知添加失败");
    }

    @PostMapping("login/email")
    @ApiOperation("邮箱登录")
    public ResponseResult<UserVo> loginByEmail(@RequestBody @Validated({UserLoginByEmail.class}) UserLoginVo user, HttpServletRequest request) {
        User result = userService.getUserByEmail(user.getEmail());
        if (result == null) {
            return ResponseResult.fail("邮箱不存在");
        }
        if (!result.getPassword().equals(user.getPassword())) {
            return ResponseResult.fail("密码错误");
        }
        if (addLoginWarning(result, request.getRemoteAddr())) {
            return ResponseResult.success(new UserVo(result));
        }
        return ResponseResult.fail("通知添加失败");
    }

    @PostMapping("register")
    @ApiOperation("用户注册")
    public ResponseResult<Serializable> register(@RequestBody @Validated UserRegisterVo user) {
        if (userService.hasUsername(user.getUsername())) {
            return ResponseResult.fail("用户名已存在");
        }
        //保存用户信息
        User saveUser = UserConverter.convert(user);
        userService.save(saveUser);
        //添加欢迎通知
        NotificationDTO notificationDTO = new NotificationDTO();
        notificationDTO.setUserId(saveUser.getId());
        notificationDTO.setType("welcome");
        notificationDTO.setMessage("欢迎使用手机商城");
        notificationDTO.setStatus("unread");
        if (notificationClient.add(notificationDTO)) {
            return ResponseResult.success();
        }
        return ResponseResult.fail("通知添加失败");
    }

    @PutMapping
    @ApiOperation("更新用户信息")
    public ResponseResult<Serializable> updateById(@RequestBody @Validated UserVo user) {
        User updateUser = new User();
        updateUser.setId(user.getId());
        if (StringUtils.hasText(user.getUsername())) {
            if (userService.hasUsername(user.getUsername())) {
                return ResponseResult.fail("用户名已存在");
            }
            updateUser.setUsername(user.getUsername());
        }
        if (StringUtils.hasText(user.getPassword())) {
            updateUser.setPassword(user.getPassword());
        }
        if (StringUtils.hasText(user.getPhone())) {
            if (userService.hasPhone(user.getPhone())) {
                return ResponseResult.fail("手机号已存在");
            }
            if (user.getPhone().length() != 11) {
                return ResponseResult.fail("手机号必须为11位");
            }
            updateUser.setPhone(user.getPhone());
        }
        if (StringUtils.hasText(user.getEmail())) {
            if (userService.hasEmail(user.getEmail())) {
                return ResponseResult.fail("邮箱已存在");
            }
            if (!user.getEmail().matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")) {
                return ResponseResult.fail("邮箱格式不正确");
            }
            updateUser.setEmail(user.getEmail());
        }
        if (StringUtils.hasText(user.getAvatar())) {
            updateUser.setAvatar(user.getAvatar());
        }
        userService.updateById(updateUser);
        return ResponseResult.success();
    }

    @GetMapping("username")
    @ApiOperation("通过用户名获取用户信息")
    public ResponseResult<UserVo> getUserByUsername(@RequestParam String username) {
        User user = userService.getUserByUsername(username);
        if (user == null) {
            return ResponseResult.fail("用户名不存在");
        }
        return ResponseResult.success(new UserVo(user));
    }

    @GetMapping("phone")
    @ApiOperation("通过手机号获取用户信息")
    public ResponseResult<UserVo> getUserByPhone(@RequestParam String phone) {
        User user = userService.getUserByPhone(phone);
        if (user == null) {
            return ResponseResult.fail("手机号不存在");
        }
        return ResponseResult.success(new UserVo(user));
    }

    @GetMapping("email")
    @ApiOperation("通过邮箱获取用户信息")
    public ResponseResult<UserVo> getUserByEmail(@RequestParam String email) {
        User user = userService.getUserByEmail(email);
        if (user == null) {
            return ResponseResult.fail("邮箱不存在");
        }
        return ResponseResult.success(new UserVo(user));
    }

    @GetMapping("notification")
    @ApiOperation("获取用户通知")
    public ResponseResult<List<NotificationDTO>> getNotification(@RequestParam("userId") Long userId, @RequestParam("isRight") Boolean isRight) {
        List<NotificationDTO> notificationDTOList = notificationClient.getByUserId(userId, isRight);
        return ResponseResult.success(notificationDTOList);
    }
}
